#ifndef RAY_H
#define RAY_H

// Precompiler options
#include "Prerequisites.h"
#include "Vector3D.h"
#include "PlaneBoundedVolume.h"


/** Representation of a ray in space, ie a line with an origin and direction. */
class Ray
{
protected:
	Vector3D mOrigin;
	Vector3D mDirection;
public:
	Ray():mOrigin(Vector3D::ZERO), mDirection(Vector3D::UNIT_Z) {}
	Ray(const Vector3D& origin, const Vector3D& direction)
		:mOrigin(origin), mDirection(direction) {}

	/** Sets the origin of the ray. */
	void setOrigin(const Vector3D& origin) {mOrigin = origin;}
	/** Gets the origin of the ray. */
	const Vector3D& getOrigin(void) const {return mOrigin;}

	/** Sets the direction of the ray. */
	void setDirection(const Vector3D& dir) {mDirection = dir;}
	/** Gets the direction of the ray. */
	const Vector3D& getDirection(void) const {return mDirection;}

	/** Gets the position of a point t units along the ray. */
	Vector3D getPoint(float t) const {
		return Vector3D(mOrigin + (mDirection * t));
	}

	/** Gets the position of a point t units along the ray. */
	Vector3D operator*(float t) const {
		return getPoint(t);
	};

	/** Tests whether this ray intersects the given plane.
	@returns A pair structure where the first element indicates whether
		an intersection occurs, and if true, the second element will
		indicate the distance along the ray at which it intersects.
		This can be converted to a point in space by calling getPoint().
	*/
	std::pair<bool, float> intersects(const Plane& p) const
	{
		return Math::intersects(*this, p);
	}
	/** Tests whether this ray intersects the given plane bounded volume.
	@returns A pair structure where the first element indicates whether
	an intersection occurs, and if true, the second element will
	indicate the distance along the ray at which it intersects.
	This can be converted to a point in space by calling getPoint().
	*/
	std::pair<bool, float> intersects(const PlaneBoundedVolume& p) const
	{
		return Math::intersects(*this, p.planes, p.outside == Plane::POSITIVE_SIDE);
	}
	/** Tests whether this ray intersects the given sphere.
	@returns A pair structure where the first element indicates whether
		an intersection occurs, and if true, the second element will
		indicate the distance along the ray at which it intersects.
		This can be converted to a point in space by calling getPoint().
	*/
	std::pair<bool, float> intersects(const Sphere& s) const
	{
		return Math::intersects(*this, s);
	}
	/** Tests whether this ray intersects the given box.
	@returns A pair structure where the first element indicates whether
		an intersection occurs, and if true, the second element will
		indicate the distance along the ray at which it intersects.
		This can be converted to a point in space by calling getPoint().
	*/
	std::pair<bool, float> intersects(const AxisAlignedBox& box) const
	{
		return Math::intersects(*this, box);
	}

};

#endif
